/*
 * Copyright (c) 2007, Olof Naessen and Per Larsson
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 *    * Redistributions of source code must retain the above copyright notice, 
 *      this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright notice, 
 *      this list of conditions and the following disclaimer in the documentation 
 *      and/or other materials provided with the distribution.
 *    * Neither the name of the Darkbits nor the names of its contributors may be 
 *      used to endorse or promote products derived from this software without 
 *      specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "levelhandler.hpp"
#include "resourcehandler.hpp"
#include "os.hpp"
#include <fstream>
#include <iostream>
#include <allegro.h>
#ifndef BALLZ_WIN32
#include <stdlib.h>
#endif

LevelHandler* LevelHandler::mInstance = 0;

LevelHandler* LevelHandler::getInstance()
{
    if (mInstance == 0)
    {
        mInstance = new LevelHandler();
    }

    return mInstance;
}

LevelHandler::LevelHandler()
:mStarsCollected(0)
{
    load();
}

LevelModel* LevelHandler::getLevel(int number)
{
    return mLevels[number];
}

void LevelHandler::destroy()
{
    unsigned int i;
    for (i = 0; i < mLevels.size(); i++)
    {
        delete mLevels[i];
    }
}

void LevelHandler::load()
{
    std::ifstream levelsFile;

    levelsFile.open(BALLZ_DATA_PREFIX"/levels.txt", std::ios::in);

    if (!levelsFile.is_open())
    {
        throw std::string("Levels default file could not be opened!");
    }
   
    while (!levelsFile.eof())
    {
        std::string name;
        std::string mapfile;
        int starsCollectedUntilUnlocked;
        int tileSet;

        getline(levelsFile, name);

        levelsFile >> mapfile;
        levelsFile >> starsCollectedUntilUnlocked;
        levelsFile >> tileSet;

        // Remove line feed
        std::string linefeed;
        getline(levelsFile, linefeed);
         
        int numberOfStars = countNumberOfStarsInMap(mapfile);
        LevelModel* levelModel = new LevelModel(name,
                                                mapfile,
                                                numberOfStars,
                                                starsCollectedUntilUnlocked,
                                                tileSet);
        mLevels.push_back(levelModel);
    }

    levelsFile.close();

    std::string saveFilename;

#if defined (BALLZ_WIN32)
    saveFilename = "data/saves.txt";
#else
    saveFilename = std::string(getenv("HOME")) + "/.ballz_saves.txt";
#endif

#if defined (BALLZ_WIN32)    
    if (exists(saveFilename.c_str()))
#else
    if (file_exists(saveFilename.c_str(), FA_HIDDEN, NULL))
#endif
    {
        std::ifstream savesFile;

        savesFile.open(saveFilename.c_str(), std::ios::out);

        if (!savesFile.is_open())
        {
            throw std::string("Saves file could not be opened! " + saveFilename);
        }

        unsigned int i;
        for (i = 0; i < mLevels.size(); i++)
        {
            savesFile >> mLevels[i]->numberOfCollectedStars;
            savesFile >> mLevels[i]->bestTime;
        }

        savesFile.close();
    }
}

void LevelHandler::save()
{
    std::ofstream file;
    std::string saveFilename;
    
#if defined (BALLZ_WIN32)
    saveFilename = "data/saves.txt";
#else
    saveFilename = std::string(getenv("HOME")) + "/.ballz_saves.txt";
#endif

    file.open(saveFilename.c_str(), std::ios::out);
        
    if (!file.is_open())
    {
        throw std::string("Saves file could not be opened for save! " + saveFilename);
    }
    
    unsigned int i;
    for (i = 0; i < mLevels.size(); i++)
    {
        file << mLevels[i]->numberOfCollectedStars << " "
             << mLevels[i]->bestTime << " ";
    }
    
    file.close();
}

int LevelHandler::getNumberOfLevels()
{
    return mLevels.size();
}

int LevelHandler::countNumberOfStarsInMap(const std::string& filename)
{
    std::string realFilename = ResourceHandler::getInstance()->getRealFilename(filename);

    std::ifstream file;
    file.open(realFilename.c_str(), std::ios::in);

    if (!file.is_open())
    {
        throw std::string("Level file could not be opened for counting stars! ") + realFilename;
    }

    int length;
    file >> length;
 
    std::string line;

    // Remove first line
    getline(file, line);

    int numberOfStars = 0;

	int i;
    for (i = 0; i < 15; i++)
    {   
        getline(file, line);

        unsigned int i;
        for (i = 0; i < line.size(); i++)
        {
            if (line[i] == '2' || line[i] == '8')
            {
                numberOfStars++;
            }
        }
    }

    file.close();

    return numberOfStars;
}

int LevelHandler::getStarsCollected()
{
    int result = 0;
    unsigned int i;
    for (i = 0; i < mLevels.size(); i++)
    {
        result += mLevels[i]->numberOfCollectedStars;
    }

    return result;
}
